package service

import (
	"encoding/json"

	"chat.com/common"
	"chat.com/library"
	"chat.com/model"
	"chat.com/pkg/logger"
	"chat.com/server/grpc/grpcclient"
	"chat.com/server/wsserver/connection"
)

/* 群聊消息服务 */
type SendResultGroupChat struct {
	Success    bool
	MsgId      int64
	SendStatus map[int64]string
}

// 发送群聊消息
func SendGroupChatMessage(req *common.WsGroupChatRequest) (sendResult SendResultGroupChat, errReturn error) {
	logger.Debug("Enter SendSingleChatMessage")
	defer logger.Debug("Exit SendSingleChatMessage")

	// 验证发送者是否是群成员
	if ok := isGroupMember(req); !ok {
		sendResult.Success = false
		errReturn = nil
		return
	}

	// 历史消息存储
	msgId, err := persistGroupChatMessage(req)
	if err != nil {
		sendResult.Success = false
		errReturn = err
		return
	}
	sendResult.MsgId = msgId

	// 获取群成员
	groupMembers, err := GetGroupMember(req)
	if err != nil {
		sendResult.Success = false
		errReturn = err
		return
	}

	// 对群成员依次发消息
	for _, groupMember := range groupMembers {
		// 当前待发送的群成员
		req.RecieverId = groupMember.Id
		// 在线本地发送消息
		if ok, _ := SendGroupChatMessageLocal(req); !ok {
			// 在线远程发送消息
			if ok, _ := sendGroupChatMessageRemote(req); !ok {
				// 离线消息存储
				if ok, _ := storeOfflineGroupChatMessage(req); !ok {
					sendResult.SendStatus[groupMember.Id] = "消息发送失败"
				}
				sendResult.SendStatus[groupMember.Id] = "消息离线存储"
			}
		}

		sendResult.SendStatus[groupMember.Id] = "消息发送成功"
	}

	sendResult.Success = true
	errReturn = nil
	return
}

// 判断是否是群成员, 是否被禁言
func isGroupMember(req *common.WsGroupChatRequest) (ok bool) {
	isMember, _ := model.IsGroupMember(req.GroupId, req.SenderId)
	isShutUp, _ := model.IsShutUpGroupMember(req.GroupId, req.SenderId)
	return isMember && isShutUp
}

// 获取所有群成员
func GetGroupMember(req *common.WsGroupChatRequest) (groupMembers []model.GroupMember, err error) {
	return model.GetGroupMember(req.GroupId)
}

// 持久化一条群消息到发件箱mysql
func persistGroupChatMessage(req *common.WsGroupChatRequest) (id int64, err error) {
	return model.NewSingleMessage(req.AppId, req.Type, req.Content, req.SenderId, req.RecieverId, req.SentTime)
}

// 删除一条群聊消息mysql
func deleteGroupChatMessage(req *common.WsGroupChatRequest) (ok bool, err error) {
	return model.DeleteSingleMessage(req.Id)
}

// 给本机用户发送群聊消息ws
func SendGroupChatMessageLocal(req *common.WsGroupChatRequest) (ok bool, err error) {
	recieverConn := connection.GetUserConnection(req.AppId, req.RecieverId)
	if recieverConn == nil {
		ok, err = false, nil
		return
	}

	data, err := json.Marshal(req)
	if err != nil {
		ok = false
		return
	}

	recieverConn.SendMessage(data)
	ok = true
	return
}

// 给非本机用户发送群聊消息grpc
func sendGroupChatMessageRemote(req *common.WsGroupChatRequest) (ok bool, err error) {
	// 从Redis获取接收者连接信息
	key := library.GetUserKey(req.AppId, req.RecieverId)
	info, err := library.GetUserOnlineInfo(key)
	if err != nil || !info.IsOnline() {
		logger.Debug("用户不在线, %d, %d, %s", req.AppId, req.RecieverId, err)
		ok = false
		return
	}

	// 通过接收者online信息中的其所在的rpc server name来发送信息给接收者
	if err = grpcclient.SendGroupChatMsg(info.RpcServerName, req); err != nil {
		ok = false
		return
	}

	ok = true
	return
}

// 离线存储群聊消息redis
func storeOfflineGroupChatMessage(req *common.WsGroupChatRequest) (ok bool, err error) {
	data, err := json.Marshal(req)
	if err != nil {
		ok = false
		return
	}

	if err = library.StoreOfflineGroupChatMsg(req.RecieverId, string(data), float64(req.SentTime)); err != nil {
		logger.Debug("消息发送失败-离线存储失败", req.AppId, req.RecieverId, err)
		ok = false
		return
	}

	logger.Debug("用户不在线, 消息已离线存储", req.AppId, req.RecieverId, err)
	ok = true
	return
}
